/*
 * CS_BUY_ITEM_WITH_ZEN.cpp
 *
 *  Created on: 2013. 5. 28.
 *      Author: the2
 */

#include "../../Command.h"
#include "../../User.h"
#include "../../NResource/Static.h"
#include "../../NLogic/Item.h"
#include "../../NLogic/Function.h"
#include "../../NLogic/Bag.h"
#include "../../NLogic/VirtualCurrency.h"
#include "../../GameLog.h"

namespace ProjectZ { namespace NCommand {

void SendFailBuyItemWithZen(User * pUser, int res, uint64_t itemSeq)
{
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();

	*pAck << static_cast<int16_t>(res);
	*pAck << pUser->GetCharacterInfo().gold;
	*pAck << pUser->GetVirtualCurrency()->GetZen();
	*pAck << itemSeq;

	pAck->MakePacket(CMD_SC_BUY_ITEM_WITH_ZEN);

	pUser->Send(pAck);
}

static bool BuyPackageItemWithZen(User * pUser, int item_tid, int quantity, std::string & packageName)
{
	NResource::ChargeItemData::Flyweight * pChargeItemData = NResource::Static::InstancePtr()->GetChargeItem()->GetFly(pUser, item_tid);
	if(NULL == pChargeItemData)
	{
		DEBUGLOG("CS_GACHYA_BOX [NULL == pChargeItemData] userseq = %d", pUser->GetUserSeq());
		SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
		return false;
	}

	NLogic::Item::Data clsData;
	clsData.tid = pChargeItemData->_TID;
	clsData.sub_type = pChargeItemData->_SHEET;
	clsData.quantity = quantity;
	clsData.class_type = pChargeItemData->_CLASSTYPE;
	NResource::Static::InstancePtr()->GetItemResource()->setItemEffect(clsData);

	int itemSubType	= NResource::Static::InstancePtr()->GetItemResource()->GetItemSubType(clsData);

	NLogic::MailBox::Mail::Data clsMailData;
	clsMailData.send_user_seq		= 0;
	clsMailData.send_user_nickname	= "GAMEVIL";
	clsMailData.recv_user_seq		= pUser->GetUserSeq();
	clsMailData.message 			= packageName.c_str();
	clsMailData.message.Append(pChargeItemData->_ITEM_NAME.c_str(), pChargeItemData->_ITEM_NAME.Len());

	// 골드 구매
	if (ITEM_SUBTYPE_GOLD == static_cast<EnumItemEquipPosition>(itemSubType))
	{
		clsMailData.gift_status		= EM_GIFT_GOLD;
		clsMailData.gold			= quantity;

		if (false == NLogic::NFunction::SendMail(pUser, clsMailData))
		{
			DEBUGLOG("%s : GOLD Mail Send Fail!!", __FUNCTION__);
			SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
			return false;
		}
		NGameLog::LogGoldInfo(pUser, BUY_GOLD_ZEN, quantity);
	}
	// 아이템 구매
	else
	{
		int sendMailCount	= 0;

		// 스택 아이템인 경우
		if (1 == NResource::Static::InstancePtr()->GetItemResource()->getItemStackType(clsData))
		{
			clsData.quantity	= quantity;
			sendMailCount			= 1;
		}
		else
		{
			// 스택 아이템이 아닌 경우 하나씩 첨부하여 발송
			clsData.quantity	= 1;
			sendMailCount			= quantity;
		}

		// 아이템 부가 정보 세팅
		if (false == NResource::Static::InstancePtr()->GetItemResource()->SetItemDataFromResource(pUser, clsData))
		{
			DEBUGLOG("%s : SetItemDataFromResource Fail!", __FUNCTION__);
			SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
			return false;
		}

		clsMailData.gift_status	= EM_GIFT_ITEM;
		clsMailData.item = clsData;

		// 메일 발송
		for (int i = 0; i < sendMailCount; i++)
		{
			if (false == NLogic::NFunction::SendMail(pUser, clsMailData))
			{
				DEBUGLOG("%s : ITEM Mail Send Fail!!", __FUNCTION__);
				SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
				return false;
			}
		}
	}
	return true;
}

void Command::CS_BUY_ITEM_WITH_ZEN(User * pUser, ::Network::Packet * pPacket) {

	PREPARE_PACKET;

	uint16_t chargeSeq = 0;

	*pPacket >> chargeSeq;

	DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : user_seq=%d, charge_seq=%d", pUser->GetUserSeq(), chargeSeq);

	NResource::ChargeItemData::Flyweight * pFly =
			NResource::Static::InstancePtr()->GetChargeItem()->GetFly(pUser, chargeSeq);

	if (pFly == NULL)
	{
		DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : pFly is NULL!!!");
		SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
		return;
	}

	if (-1 == pFly->_POSITION)
	{
		DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : Position is -1");
		SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
		return;
	}

	DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : userseq=%d, charge_seq=%d, tid=%d, sheet=%d, quantity=%d, vc_index=%d, userzen=%d, price=%d",
			pUser->GetUserSeq(), chargeSeq, pFly->_TID, pFly->_SHEET, pFly->_QUANTITY, pFly->_VC_INDEX, pUser->GetVirtualCurrency()->GetZen(), pFly->_PRICE);

	// 유저의 보유ZEN 확인
	if ((pUser->GetVirtualCurrency()->GetZen() - pFly->_PRICE) < 0)
	{
		DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : Not Enought ZEN!!");
		SendFailBuyItemWithZen(pUser, ACK_NOT_ENOUGH_ZEN, 0);
		return;
	}

	if (0 <= pFly->_PACKAGE)
	{
		NResource::PackageItemData::Flyweight * pPackageFly =
				NResource::Static::Instance().GetPackageItemResource()->GetFly(pUser->GetCompany(), pUser->GetSaleCode(), pFly->_PACKAGE);

		if (NULL == pPackageFly)
		{
			DEBUGLOG("NULL == pPackageFly chargeSeq : %d PACKAGE : %d", chargeSeq, pFly->_PACKAGE);
			SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
			return;
		}

		std::string packageName;
		packageName.append("[").append(pFly->_EXPLAIN.c_str()).append("]").append("!N");

		if (-1 < pPackageFly->_ITEM1_TID)
		{
			if (false == BuyPackageItemWithZen(pUser, pPackageFly->_ITEM1_TID, pPackageFly->_ITEM1_COUNT, packageName))
				return;
		}
		if (-1 < pPackageFly->_ITEM2_TID)
		{
			if (false == BuyPackageItemWithZen(pUser, pPackageFly->_ITEM2_TID, pPackageFly->_ITEM2_COUNT, packageName))
				return;
		}
		if (-1 < pPackageFly->_ITEM3_TID)
		{
			if (false == BuyPackageItemWithZen(pUser, pPackageFly->_ITEM3_TID, pPackageFly->_ITEM3_COUNT, packageName))
				return;
		}
		if (-1 < pPackageFly->_ITEM4_TID)
		{
			if (false == BuyPackageItemWithZen(pUser, pPackageFly->_ITEM4_TID, pPackageFly->_ITEM4_COUNT, packageName))
				return;
		}

		// VC 처리
		NLogic::NFunction::VCProcess(pUser, pFly->_VC_INDEX);

		// 응답
		::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
		*pAck << static_cast<int16_t>(ACK_OK);
		*pAck << pUser->GetCharacterInfo().gold;
		*pAck << pUser->GetVirtualCurrency()->GetZen();
		*pAck << static_cast<uint64_t>(0);
		pAck->MakePacket(CMD_SC_BUY_ITEM_WITH_ZEN);
		pUser->Send(pAck);

		return;
	}

	// 아이템 SUBTYPE 확인
	NLogic::Item::Data clsData;
	clsData.class_type	= pFly->_CLASSTYPE;
	clsData.sub_type	= pFly->_SHEET;
	clsData.tid			= pFly->_TID;

	int itemSubType	= NResource::Static::InstancePtr()->GetItemResource()->GetItemSubType(clsData);

	uint64_t itemSeq	= 0;

	// 골드 구매
	if (ITEM_SUBTYPE_GOLD == static_cast<EnumItemEquipPosition>(itemSubType))
	{
		NLogic::NFunction::ModifyGold(pUser, pFly->_QUANTITY);
		NGameLog::LogGoldInfo(pUser, BUY_GOLD_ZEN, pFly->_QUANTITY);
	}
	// 진화 포인트 구매
	else if (ITEM_SUBTYPE_EV_POINT == static_cast<EnumItemEquipPosition>(itemSubType))
	{
		int ep_current = pUser->GetCharacterInfo().ep_current + pFly->_QUANTITY;
		if (ep_current >= 1000)
		{
			SendFailBuyItemWithZen(pUser, ACK_EVOLUTION_POINT_OVERFLOW, 0);
			return;
		}

		pUser->GetCharacterInfo().ep_current = ep_current;

		if (ep_current >= static_cast<int>(pUser->GetCharacterInfo().ep_max))
		{
			pUser->GetCharacterInfo().ep_max = ep_current;
		}

		// 진화포인트 구매 후 Flush.
		pUser->FlushCharacterInfo();
	}
	else if (ITEM_SUBTYPE_STAMINA == static_cast<EnumItemEquipPosition>(itemSubType))
	{
		if (false == NResource::Static::Instance().GetContentsOpenResource()->IsOpen(static_cast<int>(ContentsOpen::STAMINA_SYSTEM)))
		{
			SendFailBuyItemWithZen(pUser, ACK_NOT_OPEN, 0);
			return;
		}

		int cur_stamina = pUser->GetCharacterInfo().cur_stamina + pFly->_QUANTITY;
		if (cur_stamina >= STAMINA_MAX_CHARGE)
		{
			SendFailBuyItemWithZen(pUser, ACK_STAMINA_MAX_OVERFLOW, 0);
			return;
		}

		pUser->GetCharacterInfo().cur_stamina = cur_stamina;

		// 체력치 구매 후 Flush.
		pUser->FlushCharacterInfo();
	}
	// 아이템 구매
	else
	{
		if (false == NResource::Static::InstancePtr()->GetItemResource()->SetItemFromXLS(pUser, clsData, pFly->_SHEET, pFly->_TID, pFly->_QUANTITY))
		{
			DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : SetItemFromXLS FAIL!!!. userseq=%d", pUser->GetUserSeq());
			SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
			return;
		}

		clsData.bag_type = NResource::Static::InstancePtr()->GetItemResource()->GetItemBagType(clsData);

		NLogic::Bag * pBag = pUser->GetBag(static_cast<INVEN_BAG_TYPE>(clsData.bag_type));
		if (NULL == pBag)
		{
			DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : pBag is NULL!!! bagtype=%d", clsData.bag_type);
			SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
			return;
		}

		// 마을 입장전에 상점에서 아이템을 구매하는 경우가 있으므로
		// 여기서 인벤토리 정보 로딩
		if (false == pBag->IsLoad())
		{
			if (false == pBag->ItemLoadFromDatabase())
			{
				SendFailBuyItemWithZen(pUser, ACK_DB_ERROR, 0);
				return;
			}
		}

		int subType = NResource::Static::InstancePtr()->GetItemResource()->GetItemSubType(clsData);

		// 탈것, 스탯초기화마석, 스킬초기화마석에 대해 중복 구매 방지
		if (subType == ITEM_EQUIP_POS_VEHICLE)
		{
			if (true == pBag->IsExistSameItem(clsData))
			{
				SendFailBuyItemWithZen(pUser, ACK_ALREADY_BUY_ITEM, itemSeq);
				return;
			}
		}

		bool bBagFull = false;
		NLogic::Item * pItem = pBag->AddItemWithData(clsData, bBagFull);

		if (true == bBagFull)
		{
			SendFailBuyItemWithZen(pUser, ACK_INVEN_BAG_FULL, 0);
			return;
		}

		if (NULL == pItem)
		{
			DEBUGLOG("CS_BUY_ITEM_WITH_ZEN : pItem is NULL!!!");
			SendFailBuyItemWithZen(pUser, ACK_UNKNOWN_ERROR, 0);
			return;
		}

		itemSeq = pItem->GetItemSeq();
	}

	// VC 처리
	NLogic::NFunction::VCProcess(pUser, pFly->_VC_INDEX);

	// 응답
	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	*pAck << static_cast<int16_t>(ACK_OK);
	*pAck << pUser->GetCharacterInfo().gold;
	*pAck << pUser->GetVirtualCurrency()->GetZen();
	*pAck << itemSeq;
	pAck->MakePacket(CMD_SC_BUY_ITEM_WITH_ZEN);
	pUser->Send(pAck);
}

} /*NCommand*/ } /*ProjectZ*/
